/* Editor.h
Copyright (c) 2008 Michael Zahniser
Please note the license terms (MIT license) at the end of this document.

Header file for the Hexie Editor class, which receives user input and edits a Hexie
Document, and also provides information to the Display on how to draw that document.
*/

#ifndef __HEXIE_EDITOR_H__
#define __HEXIE_EDITOR_H__

#include "SDL.h"
#include "Document.h"
#include "_sdl/KeyHandler.h"

#include <string>
#include <map>
#include <set>
#include <vector>

using std::string;
using std::map;
using std::set;
using std::vector;



class Editor {
public:
	// TODO: Handle all the constants more cleanly. Maybe load them from preferences.
	static const int COLUMNS;
	static const int ROWS;
	
	// This is the coordinates of a cell of data.
	class Cell {
	public:
		short row;
		short column;
	};
	
	
public:
	// Default constructor sets up the key event map.
	Editor();
	
	// Load the given file.
	void Load(const string &filePath);
	
	// Handle the given SDL key event.
	void Handle(SDLKey key, SDLMod mod);
	// Handle the given mouse event.
	void HandleMouse(const SDL_Event &event);
	// This flag is set when the user sends a quit command.
	bool IsDone() const;
	
	// Get the document that is being edited. Only Editor may change it,
	// but others may view it.
	const Document &GetDocument() const;
	// Get the line start iterators. This vector has one sentinel iterator at its end
	// that points to past the end of the document.
	const vector<Document::It> &Lines() const;
	
	// Get the cell containing the given data.
	// If the returned cell's column is -1, it is not visible.
	Cell CellOf(Document::It it) const;
	// Place the cursor in the given cell position, keeping the same anchor if
	// keepAnchor is true. The cell coordinates are cropped to the view bounds.
	void PlaceCursor(Cell cell, bool keepAnchor);
	// Scroll to put the given row of the document at the top of the view.
	// If the given value is out of range, it will be cropped appropriately.
	void ScrollToRow(int row);

	// Get the number of actual rows of data that are visible on screen.
	// It may be less than the number of rows in the display if the file is small.
	// So it isn't safe, for example, to assume that lines[ROWS] exists, but
	// lines[VisibleRows()] will always be the sentinel at the end of lines.
	int VisibleRows() const;
	// Get the total number of rows of data.
	int TotalRows() const;
	// Get the row to which the display is currently scrolled.
	int ScrollRow() const;
	
	
private:
	// Calculate line offsets, taking any line breaks into account.
	// Scroll such that the given character is at the top of the screen.
	void CalculateLines(Document::It line);
	// Scroll so that the cursor is on screen. If the cursor is in the current view,
	// do nothing. If it is above the current view, scroll so that it is in the top
	// line. If below, scroll so that it is in the bottom line.
	void ScrollToCursor();
	// Scroll up (updating the lines vector in the process).
	bool ScrollUp();
	// Scroll down (updating the lines vector in the process).
	bool ScrollDown();

	// Update the cursor cell position based on the document.
	void UpdateCursorCell();
	// Move the cursor in the document to match the cursor cell position.
	void PlaceCursor(bool keepAnchor);
	
	// Count the number of rows of the document up to the given point.
	int RowsBefore(Document::It end) const; 
	// Count the number of rows between two iterators.
	int RowsBetween(Document::It first, Document::It last) const;

	// Event handlers:
	void OnEndianToggle(SDLKey key, SDLMod mod);
	void OnLeft(SDLKey key, SDLMod mod);
	void OnRight(SDLKey key, SDLMod mod);
	void OnUp(SDLKey key, SDLMod mod);
	void OnDown(SDLKey key, SDLMod mod);
	void OnNext(SDLKey key, SDLMod mod);
	void OnDelete(SDLKey key, SDLMod mod);
	void OnBreak(SDLKey key, SDLMod mod);
	void OnQuit(SDLKey key, SDLMod mod);
	void OnEscape(SDLKey key, SDLMod mod);
	// Default key handler.
	void OnKey(SDLKey key, SDLMod mod);


private:
	// The file that is being viewed and marked up.
	Document document;
	// These are the beginnings of the lines currently visible on the screen.
	vector<Document::It> lines;
	// This is where the cursor "wants" to be. If we're currently on a line with
	// fewer columns of data, the cursor will appear instead in the last column
	// of the row.
	Cell cursorCell;

	// Object for dispatching key events to different functions.
	KeyHandler<Editor> handler;

	// This flag is set by any key handler that recognizes a quit command.
	bool isDone;
};



#endif

/* Copyright (c) 2008 Michael Zahniser

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE. */
